﻿using ADRcpLib;
using ADSioLib;
using log4net;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using VirtualWall.Models;

namespace VirtualWall
{
    public class FlowControl
    {
        #region 相关属性
        private static readonly ILog log = LogManager.GetLogger("VirtualWall");
        private VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK m_PlateResultCB1 = null;
        private VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK m_PlateResultCB2 = null;
        public string m_in_PlateNo;  //进场车牌号码存储变量
        public string m_out_PlateNo;  //出场车牌号码存储变量


        public System.Timers.Timer time_video = new System.Timers.Timer(15 * 1000);


        //车牌识别相机句柄
        int handle1 = 0;
        int handle2 = 0;
        int serial_handle1 = 0;
        int serial_handle2 = 0;

        //识别相机是否在线的状态标记
        byte stat1 = 0;
        byte stat2 = 0;

        //远程读卡器串口 新版
        public static SioBase SioBase = new SioNet();
        public static RcpBase RcpBase = new RcpBase();
        public static SioBase SioBase2 = new SioNet();
        public static RcpBase RcpBase2 = new RcpBase();

        public bool IsConnectedSio
        {
            get
            {
                if (SioBase == null) return false;
                if (!SioBase.bConnected) return false;
                return true;
            }
        }
        public bool IsConnectedSio2
        {
            get
            {
                if (SioBase2 == null) return false;
                if (!SioBase2.bConnected) return false;
                return true;
            }
        }

        /// <summary>
        /// 进出场图片保存的根目录
        /// </summary>
        public string SavePath { get { return Environment.CurrentDirectory + "\\Snap\\Temp\\"; } }

        #endregion

        ///尝试启动逻辑
        public static void TryRun()
        {
            log.Info("App is Runing");
            //根据启动时传递的参数，决定初始化远程刷卡器或者车牌识别相机
            var m_Mode = ConfigurationManager.AppSettings["VirtualWall"];
            var flowControl = new FlowControl();
            AppContext.FlowControl = flowControl;
            flowControl.time_video.AutoReset = false;
            flowControl.time_video.Elapsed += Time_video_Elapsed;

            switch (m_Mode)
            {
                case "1"://高频读头
                    {
                        flowControl.InitSioBase();
                    }
                    break;
                case "2"://高频读头+ 车牌识别
                    {
                        VzClientSDK.VzLPRClient_Setup();
                        flowControl.InitCamera();

                        //启动的时候将进入场相机设置为放下状态
                        if (flowControl.handle1 != 0)
                        {
                            log.Info("0x08F0 第一个 启动时候设关：" + VzClientSDK.VzLPRClient_SetIOOutput(flowControl.handle1, 0, 0));
                            Thread.Sleep(500);
                        }
                        if (flowControl.handle2 != 0)
                        {
                            log.Info("0x08F0 第二个 启动时设管：" + VzClientSDK.VzLPRClient_SetIOOutput(flowControl.handle2, 0, 0));
                            Thread.Sleep(500);
                        }

                        flowControl.InitSioBase();

                        //貌似是定期检测相机是否在线
                        var connStatTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(10) };
                        connStatTimer.Start();
                        connStatTimer.Tick += (sender, args) =>
                        {
                            if (flowControl.handle1 != 0) VzClientSDK.VzLPRClient_IsConnected(flowControl.handle1, ref flowControl.stat1);
                            if (flowControl.handle2 != 0) VzClientSDK.VzLPRClient_IsConnected(flowControl.handle2, ref flowControl.stat2);
                            if (flowControl.stat1 == 0 || flowControl.stat2 == 0)
                            {
                                log.Info($"检测到车牌相机{(flowControl.stat1 == 0 ? "1" : flowControl.stat2 == 0 ? "2" : "")}掉线");
                                flowControl.InitCamera();
                            }

                        };
                    }
                    break;
            }

        }

        private static void Time_video_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                var time = sender as System.Timers.Timer;

                if (time == null)
                {
                    return;
                }

                //停止录像
                var flag = VzClientSDK.VzLPRClient_StopSaveRealData(AppContext.FlowControl.handle2);
                //time.Stop();

                ////执行闸机在车辆出场时的动作
                AppContext.FlowControl.GoOut(AppContext.FlowControl.m_out_PlateNo);
            }
            catch { }
        }

        #region 车牌识别相机

        /// <summary>
        /// 初始化加载拍照识别相机
        /// </summary>
        /// <returns></returns>
        private void InitCamera()
        {
            if (handle1 == 0)//围栏进场摄像头
            {
                var cameraUser = ConfigurationManager.AppSettings["VWCamera1Username"];
                var cameraPwd = ConfigurationManager.AppSettings["VWCamera1Password"];
                //handle1 = VzClientSDK.VzLPRClient_Open(ConfigurationManager.AppSettings["VWCamera1IP"], 80, "admin", "admin");
                handle1 = VzClientSDK.VzLPRClient_Open(ConfigurationManager.AppSettings["VWCamera1IP"], 80, cameraUser, cameraPwd);

                if (handle1 != 0)
                {
                    stat1 = 1;
                    log.Info("Camera1 Login Success");
                    //获取车牌信息
                    m_PlateResultCB1 = new VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK(OnPlateInResult);
                    VzClientSDK.VzLPRClient_SetPlateInfoCallBack(handle1, m_PlateResultCB1, IntPtr.Zero, 1);
                }
                else
                {
                    log.Info("Camera1 Login Failed");
                }
            }

            if (handle2 == 0)//围栏出场摄像头
            {
                var cameraUser = ConfigurationManager.AppSettings["VWCamera2Username"];
                var cameraPwd = ConfigurationManager.AppSettings["VWCamera2Password"];
                //handle2 = VzClientSDK.VzLPRClient_Open(ConfigurationManager.AppSettings["VMCamera2IP"], 80, "admin", "admin");
                handle2 = VzClientSDK.VzLPRClient_Open(ConfigurationManager.AppSettings["VWCamera2IP"], 80, cameraUser, cameraPwd);
                if (handle2 != 0)
                {
                    stat2 = 1;
                    log.Info("Camera2 Login Success");
                    //获取车牌信息
                    m_PlateResultCB2 = new VzClientSDK.VZLPRC_PLATE_INFO_CALLBACK(OnPlateOutResult);
                    VzClientSDK.VzLPRClient_SetPlateInfoCallBack(handle2, m_PlateResultCB2, IntPtr.Zero, 1);
                }
                else
                {
                    log.Info("Camera2 Login Failed");
                }
            }
        }

        /// <summary>
        /// 初始化加载高频读头
        /// </summary>
        private void InitSioBase()
        {
            try
            {
                SioBase.onStatus += SioBase_onStatus;
                SioBase.onReceived += SioBase_onReceived;
                RcpBase.RxRspParsed += RcpBase_RxRspParsed;
                if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["VWRF3Ip"]))
                {
                    SioBase.Connect(ConfigurationManager.AppSettings["RF3IP"], 49152);
                }
                SioBase2.onStatus += SioBase2_onStatus;
                SioBase2.onReceived += SioBase2_onReceived;
                RcpBase2.RxRspParsed += RcpBase2_RxRspParsed;
                if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["VWRF4Ip"]))
                {
                    SioBase2.Connect(ConfigurationManager.AppSettings["RF4IP"], 49152);
                }

            }
            catch (Exception e)
            {
                log.Error($"InitSioBase Failed!{e.Message}");
            }

        }

        #region 围栏识别相机的回调函数
        /// <summary>
        /// 入场摄像头识别后执行的操作，需要记录当前车牌的
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="pUserData"></param>
        /// <param name="pResult"></param>
        /// <param name="uNumPlates"></param>
        /// <param name="eResultType"></param>
        /// <param name="pImgFull"></param>
        /// <param name="pImgPlateClip"></param>
        /// <returns></returns>
        private int OnPlateInResult(int handle, IntPtr pUserData, IntPtr pResult, uint uNumPlates,
            VzClientSDK.VZ_LPRC_RESULT_TYPE eResultType, IntPtr pImgFull, IntPtr pImgPlateClip)
        {
            if (eResultType != VzClientSDK.VZ_LPRC_RESULT_TYPE.VZ_LPRC_RESULT_REALTIME)
            {
                VzClientSDK.TH_PlateResult result = (VzClientSDK.TH_PlateResult)Marshal.PtrToStructure(pResult, typeof(VzClientSDK.TH_PlateResult));
                string strLicense = new string(result.license);
                strLicense = strLicense.Replace("\0", "");

                if (strLicense == "_无_") return 0;
                if (strLicense == "无牌车") return 0;

                byte[] strDecIP = new byte[32];
                VzClientSDK.VzLPRClient_GetDeviceIP(handle, ref strDecIP[0], 32);
                string strIP = Encoding.Default.GetString(strDecIP).TrimEnd('\0');

                string tempPicPath = SavePath + strLicense + "_in.jpg";
                VzClientSDK.VzLPRClient_ImageSaveToJpeg(pImgFull, tempPicPath, 100);

                m_in_PlateNo = strLicense;
                //执行闸机在车辆进入时的动作
                GoIn(m_in_PlateNo);
                //仅仅作记录
                log.Info(strIP + " 检测到车牌 " + strLicense);
            }

            return 0;
        }

        /// <summary>
        /// 出场摄像头识别后执行的操作
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="pUserData"></param>
        /// <param name="pResult"></param>
        /// <param name="uNumPlates"></param>
        /// <param name="eResultType"></param>
        /// <param name="pImgFull"></param>
        /// <param name="pImgPlateClip"></param>
        /// <returns></returns>
        private int OnPlateOutResult(int handle, IntPtr pUserData, IntPtr pResult, uint uNumPlates,
          VzClientSDK.VZ_LPRC_RESULT_TYPE eResultType, IntPtr pImgFull, IntPtr pImgPlateClip)
        {
            if (eResultType != VzClientSDK.VZ_LPRC_RESULT_TYPE.VZ_LPRC_RESULT_REALTIME)
            {
                VzClientSDK.TH_PlateResult result = (VzClientSDK.TH_PlateResult)Marshal.PtrToStructure(pResult, typeof(VzClientSDK.TH_PlateResult));
                string strLicense = new string(result.license);
                strLicense = strLicense.Replace("\0", "");

                if (strLicense == "_无_") return 0;
                if (strLicense == "无牌车") return 0;


                byte[] strDecIP = new byte[32];
                VzClientSDK.VzLPRClient_GetDeviceIP(handle, ref strDecIP[0], 32);
                string strIP = Encoding.Default.GetString(strDecIP).TrimEnd('\0');

                //启动录像

                //VzClientSDK.VzLPRClient_StopSaveRealData(AppContext.FlowControl.handle2);
                //Thread.Sleep(100);
                //time_video = new System.Timers.Timer();
                //time_video.Elapsed += Time_video_Elapsed;
                string tempVideoPath = SavePath + strLicense + "_out.avi";
                var flag = VzClientSDK.VzLPRClient_SaveRealData(handle, tempVideoPath);
                time_video.Start();


                string tempPicPath = SavePath + strLicense + "_out.jpg";
                flag= VzClientSDK.VzLPRClient_ImageSaveToJpeg(pImgFull, tempPicPath, 100);

                m_out_PlateNo = strLicense;
                AppContext.CurrentOutPlate = m_out_PlateNo;
                ////执行闸机在车辆出场时的动作
                //GoOut(m_out_PlateNo);
                log.Info(strIP + " 检测到车牌 " + strLicense);
            }

            return 0;
        }

        /// <summary>
        /// 围栏闸栏发送消息显示LED，和播放语音函数
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="line1"></param>
        /// <param name="line2"></param>
        /// <param name="line3"></param>
        /// <param name="line4"></param>
        /// <param name="tts"></param>
        /// <param name="rgb"></param>
        private void SendMsgToCameraLED(int handle, string line1, string line2, string line3, string line4, string tts, string rgb)
        {
            line1 = Str2Hex(line1);
            line2 = Str2Hex(line2);
            line3 = Str2Hex(line3);
            line4 = Str2Hex(line4);
            tts = Str2Hex(tts);
            string line1Len = Convert.ToString(line1.Length / 3, 16).ToUpper().PadLeft(2, '0');
            string line2Len = Convert.ToString(line2.Length / 3, 16).ToUpper().PadLeft(2, '0');
            string line3Len = Convert.ToString(line3.Length / 3, 16).ToUpper().PadLeft(2, '0');
            string line4Len = Convert.ToString(line4.Length / 3, 16).ToUpper().PadLeft(2, '0');
            string ttsLen = Convert.ToString(tts.Length / 3, 16).ToUpper().PadLeft(2, '0');

            string strHead = "00 64 FF FF 6E DL 00 04 ";
            string strLine1 = "00 01 01 05 00 R G 00 00 DL DATA";
            string strLine2 = "01 01 01 05 00 R G 00 00 DL DATA";
            string strLine3 = "02 01 01 05 00 R G 00 00 DL DATA";
            string strLine4 = "03 01 01 05 00 R G 00 00 DL DATA";
            string strTTS = "0A VTL DATA";

            if (rgb == "r")
            {
                strLine1 = strLine1.Replace("R", "FF").Replace("G", "00");
                strLine2 = strLine2.Replace("R", "FF").Replace("G", "00");
                strLine3 = strLine3.Replace("R", "FF").Replace("G", "00");
                strLine4 = strLine4.Replace("R", "FF").Replace("G", "00");
            }
            else if (rgb == "g")
            {
                strLine1 = strLine1.Replace("R", "00").Replace("G", "FF");
                strLine2 = strLine2.Replace("R", "00").Replace("G", "FF");
                strLine3 = strLine3.Replace("R", "00").Replace("G", "FF");
                strLine4 = strLine4.Replace("R", "00").Replace("G", "FF");
            }
            strLine1 = strLine1.Replace("DL", line1Len).Replace("DATA", line1);
            strLine2 = strLine2.Replace("DL", line2Len).Replace("DATA", line2);
            strLine3 = strLine3.Replace("DL", line3Len).Replace("DATA", line3);
            strLine4 = strLine4.Replace("DL", line4Len).Replace("DATA", line4);
            strTTS = strTTS.Replace("VTL", ttsLen).Replace("DATA", tts);

            string data = strLine1 + "0D " + strLine2 + "0D " + strLine3 + "0D " + strLine4 + "00 " + strTTS + "00 ";
            string dataLen = Convert.ToString(data.Length / 3 + 2, 16).ToUpper().PadLeft(2, '0');

            strHead = strHead.Replace("DL", dataLen);
            data = strHead + data;
            string strcrc = CRC.ToModbusCRC16(data, true);
            strcrc = strcrc.Insert(2, " ");
            data = data + strcrc;

            byte[] send_buf = new byte[1024];
            string new_content = data.Insert(data.Length, " ");
            int txt_len = new_content.Length;
            char[] txt_buf = new_content.ToCharArray();

            int index = 0;

            char[] strHex = new char[3];
            byte uc;
            for (int i = 0; i < txt_len - 2; i += 3)
            {
                if (txt_buf[i + 2] != ' ')
                {
                    MessageBox.Show("16 进制数据输入格式不正确");
                    return;
                }

                strHex[0] = txt_buf[i];
                strHex[1] = txt_buf[i + 1];
                strHex[2] = (char)0;

                for (int j = 0; j < 2; j++)
                {
                    if (strHex[j] < '0' || (strHex[j] > '9' && strHex[j] < 'A') || (strHex[j] > 'F' &&
                        strHex[j] < 'a') || strHex[j] > 'f')
                    {
                        MessageBox.Show("16 进制数据输入格式不正确");
                        return;
                    }
                }

                string hex_value = new string(strHex);
                uc = byte.Parse(hex_value, System.Globalization.NumberStyles.HexNumber);
                send_buf[index] = uc;
                index++;
            }

            GCHandle hObject = GCHandle.Alloc(send_buf, GCHandleType.Pinned);
            IntPtr pObject = hObject.AddrOfPinnedObject();

            VzClientSDK.VzLPRClient_SerialSend(handle, pObject, index);

            if (hObject.IsAllocated)
                hObject.Free();
        }

        #endregion

        #region 高频设备的回调函数


        public void SendSio(ProtocolPacket protocolPacket)
        {
            if (IsConnectedSio)
            {
                RcpBase.ShowBytePack(protocolPacket);
                SioBase.Send(protocolPacket.ToArray());
            }
        }

        private void SioBase_onStatus(object sender, StatusEventArgs e)
        {
            try
            {
                switch ((StatusType)e.Status)
                {
                    case StatusType.CONNECT_OK:
                        try
                        {
                            int intVer = Convert.ToInt32(e.Msg);
                        }
                        catch { }
                        log.Info("CONNECTED OK> " + e.Msg + "(" + SioBase.ToString() + ")");
                        break;
                    case StatusType.CONNECT_FAIL:
                        log.Info("ERROR> " + e.Msg + "(" + SioBase.ToString() + ")");
                        break;
                    case StatusType.DISCONNECT_OK:
                        log.Info("DISCONNECT OK> " + e.Msg + "(" + SioBase.ToString() + ")");
                        break;
                    case StatusType.DISCONNECT_EXCEPT:
                        log.Info("ERROR> " + e.Msg + "(" + SioBase.ToString() + ")");
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                log.Info(ex.ToString());
            }
        }

        private void SioBase_onReceived(object sender, ReceivedEventArgs e)
        {
            RcpBase.ReciveBytePkt(e.Data);
        }

        private void RcpBase_RxRspParsed(object sender, ProtocolEventArgs e)
        {
            try
            {
                log.Info("Rx> " + TagInfo.ByteArrayToHexString(e.Data));
                __ParseRsp(e.Protocol);
            }
            catch (Exception ex)
            {
                log.Info(ex.ToString());
            }
        }

        private void SioBase2_onStatus(object sender, StatusEventArgs e)
        {
            try
            {
                switch ((StatusType)e.Status)
                {
                    case StatusType.CONNECT_OK:
                        try
                        {
                            int intVer = Convert.ToInt32(e.Msg);
                        }
                        catch { }
                        log.Info("CONNECTED OK> " + e.Msg + "(" + SioBase2.ToString() + ")");
                        break;
                    case StatusType.CONNECT_FAIL:
                        log.Info("ERROR> " + e.Msg + "(" + SioBase2.ToString() + ")");
                        break;
                    case StatusType.DISCONNECT_OK:
                        log.Info("DISCONNECT OK> " + e.Msg + "(" + SioBase2.ToString() + ")");
                        break;
                    case StatusType.DISCONNECT_EXCEPT:
                        log.Info("ERROR> " + e.Msg + "(" + SioBase2.ToString() + ")");
                        break;
                    default:
                        break;
                }
            }
            catch (Exception ex)
            {
                log.Info(ex.ToString());
            }
        }

        private void SioBase2_onReceived(object sender, ReceivedEventArgs e)
        {
            RcpBase2.ReciveBytePkt(e.Data);
        }

        private void RcpBase2_RxRspParsed(object sender, ProtocolEventArgs e)
        {
            try
            {
                log.Info("Rx> " + TagInfo.ByteArrayToHexString(e.Data));
                __ParseRsp2(e.Protocol);
            }
            catch (Exception ex)
            {
                log.Info(ex.ToString());
            }
        }

        private int GetCodelen(byte iData)
        {
            return (((iData >> 3) + 1) * 2);
        }

        private string GetRssi(byte rssi)
        {
            int rssidBm = (sbyte)rssi; // rssidBm is negative && in bytes
            rssidBm -= Convert.ToInt32("-20", 10);
            rssidBm -= Convert.ToInt32("3", 10);
            return rssidBm.ToString();
        }

        private void __ParseRsp(ProtocolPacket protocolPacket)
        {
            switch (protocolPacket.Code)
            {
                case RcpBase.RCP_CMD_INFO:
                    if (protocolPacket.Length > 30 && (protocolPacket.Type & 0x7f) == 0)
                    {
                        #region ---Parameter---
                        string strInfo = Encoding.ASCII.GetString(protocolPacket.Payload, 0, protocolPacket.Length);
                        log.Info("Type:" + RcpBase.Mode + RcpBase.Type + " - Version:" + RcpBase.Version + " - Address: " + RcpBase.Address);
                        #endregion
                    }
                    break;

                case RcpBase.RCP_MM_READ_C_UII:
                    if (protocolPacket.Type == 2 || protocolPacket.Type == 5)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - 2;//去掉天线号去掉rssi
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,//去掉天线号去掉RSSI
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2),
                            Rssi = GetRssi(protocolPacket.Payload[protocolPacket.Length - 1]) + "dBm"
                        };
                        if ((datalen - pcepclen) > 0) cp.DataBytes = TagInfo.GetData(protocolPacket.Payload, 1 + pcepclen, datalen - pcepclen);

                        CarLabelModel carLabel = SQLDataAccess.LoadCarLabel(cp.EPCString);
                        if (carLabel != null)
                        {
                            if (carLabel.PlateNo != m_in_PlateNo)
                            {
                                m_in_PlateNo = carLabel.PlateNo;
                                //车辆进场要执行的动作
                                GoIn(m_in_PlateNo);
                                log.Info("读卡器1," + cp.EPCString + "," + carLabel.PlateNo);

                            }
                        }
                        else
                        {
                            log.Info("卡号: " + cp.EPCString + " 未查询到车号");
                        }
                    }

                    break;
                case RcpBase.RCP_MM_READ_C_DT:
                    if (protocolPacket.Type == 0)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - pcepclen - 1;//去掉天线号去掉PC+EPc
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2),
                            DataBytes = TagInfo.GetData(protocolPacket.Payload, 1 + pcepclen, datalen)
                        };
                    }
                    break;
                case RcpBase.RCP_MM_WRITE_C_DT:
                    if (protocolPacket.Type == 0)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - pcepclen - 1;//去掉天线号去掉PC+EPc
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2)
                        };
                    }
                    break;
                case RcpBase.RCP_MM_GET_ACCESS_EPC_MATCH:
                    break;
                case RcpBase.RCP_MM_SET_ACCESS_EPC_MATCH:
                    break;
                default:
                    break;
            }
        }
        private void __ParseRsp2(ProtocolPacket protocolPacket)
        {
            switch (protocolPacket.Code)
            {
                case RcpBase.RCP_CMD_INFO:
                    if (protocolPacket.Length > 30 && (protocolPacket.Type & 0x7f) == 0)
                    {
                        #region ---Parameter---
                        string strInfo = Encoding.ASCII.GetString(protocolPacket.Payload, 0, protocolPacket.Length);

                        log.Info("Type:" + RcpBase.Mode + RcpBase.Type + " - Version:" + RcpBase.Version + " - Address: " + RcpBase.Address);
                        #endregion
                    }
                    break;

                case RcpBase.RCP_MM_READ_C_UII:
                    if (protocolPacket.Type == 2 || protocolPacket.Type == 5)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - 2;//去掉天线号去掉rssi
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,//去掉天线号去掉RSSI
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2),
                            Rssi = GetRssi(protocolPacket.Payload[protocolPacket.Length - 1]) + "dBm"
                        };
                        if ((datalen - pcepclen) > 0) cp.DataBytes = TagInfo.GetData(protocolPacket.Payload, 1 + pcepclen, datalen - pcepclen);

                        CarLabelModel carLabel = SQLDataAccess.LoadCarLabel(cp.EPCString);
                        if (carLabel != null)
                        {
                            if (carLabel.PlateNo != m_out_PlateNo)
                            {
                                m_out_PlateNo = carLabel.PlateNo;
                                AppContext.CurrentOutPlate = m_out_PlateNo;
                                //车辆出场后执行的动作
                                GoOut(m_out_PlateNo);
                                log.Info("读卡器2," + cp.EPCString + "," + carLabel.PlateNo);
                            }
                        }
                        else
                        {
                            log.Info("卡号: " + cp.EPCString + " 未查询到车号");
                        }
                    }

                    break;
                case RcpBase.RCP_MM_READ_C_DT:
                    if (protocolPacket.Type == 0)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - pcepclen - 1;//去掉天线号去掉PC+EPc
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2),
                            DataBytes = TagInfo.GetData(protocolPacket.Payload, 1 + pcepclen, datalen)
                        };
                    }
                    break;
                case RcpBase.RCP_MM_WRITE_C_DT:
                    if (protocolPacket.Type == 0)
                    {
                        int pcepclen = GetCodelen(protocolPacket.Payload[1]);
                        int datalen = protocolPacket.Length - pcepclen - 1;//去掉天线号去掉PC+EPc
                        TagInfo cp = new TagInfo
                        {
                            TagType = TagType.TYPE_6C,
                            Length = datalen,
                            Antenna = protocolPacket.Payload[0],
                            PCData = TagInfo.GetData(protocolPacket.Payload, 1, 2),
                            EPCData = TagInfo.GetData(protocolPacket.Payload, 3, pcepclen - 2)
                        };
                    }
                    break;
                case RcpBase.RCP_MM_GET_ACCESS_EPC_MATCH:
                    break;
                case RcpBase.RCP_MM_SET_ACCESS_EPC_MATCH:
                    break;
                default:
                    break;
            }
        }

        #endregion

        #endregion

        #region 车辆进出入动作

        /// <summary>
        /// 车辆进入的时候要执行的动作
        /// </summary>
        /// <param name="pateNo">车牌号</param>
        private void GoIn(string pateNo)
        {
            //打开485串口
            VzClientSDK.VZDEV_SERIAL_RECV_DATA_CALLBACK serial_recv_ = null;
            serial_handle1 = VzClientSDK.VzLPRClient_SerialStart(handle1, 0, serial_recv_, IntPtr.Zero);
            if (serial_handle1 == 0)
            {
                log.Info("相机1的485串口1打开失败!");
            }
            bool flag = true;
            var mess = $"{pateNo}欢迎光临";
            //如果有，查询车牌白名单
            if (ConfigurationManager.AppSettings["VWWhiteListeEnable"] == "1")
            {
                var carInfo = SQLDataAccess.LoadCar(pateNo);
                if (carInfo == null)
                {
                    log.Debug("识别到非白名单中的车牌:" + pateNo);
                    mess = $"{pateNo}未授权";
                    flag = false;
                }
                else if (carInfo.enddate > DateTime.Now)//超过有效期限
                {
                    log.Debug("识别到超过有效期限的车牌:" + pateNo);
                    mess = $"{pateNo}已过期";
                    flag = false;
                }
            }

            //发送语音数据
            //TTSHelper.TTS(mess);
            //发送LED显示数据
            SendMsgToCameraLED(serial_handle1, "车牌识别", mess, DateTime.Now.ToString(), "双髻鲨汽车衡称重", mess, "g");

            if (flag)
            {

                //检查是否多次被拍摄而抬杆但没有进去的，这个时候就检查是否未完成的停车记录，
                ////如果有则表明他触发了入场抬杆，但没有进去的情况。这个时候
                //就不再新增数据，而是继续使用未完成的那条停车记录。
                var noFinish = SQLDataAccess.CarFeeNoFinish(pateNo);
                if (noFinish == null)//表明需要新增入场停车记录
                {
                    SQLDataAccess.SaveCarFee(new Models.CarFeeModel() { PlateNo = m_in_PlateNo, InDate = DateTime.Now });
                }

                mess = $"{pateNo}欢迎光临";
                //抬杆
                log.Info("0x08F0 第一个 开：" + VzClientSDK.VzLPRClient_SetIOOutput(handle1, 0, 1));
                Thread.Sleep(500);
                log.Info("0x08F0 第一个 关：" + VzClientSDK.VzLPRClient_SetIOOutput(handle1, 0, 0));
                Thread.Sleep(500);
            }

        }

        /// <summary>
        /// 车辆出去的时候要执行的动作
        /// </summary>
        /// <param name="pateNo">车牌号</param>
        public void GoOut(string pateNo)
        {
            var mess = string.Empty;
            //进行数据库查询，检查称重记录是否完整、费用是否缴清（暂不做处理）
            //查询称重记录是否完整
            //var WH_Record = SQLDataAccess.LoadWeighingRecord(pateNo, false);
            //var WH_Record = SQLDataAccess.GetWeighingRecord(pateNo);
            var noFinish = SQLDataAccess.CarFeeNoFinish(pateNo);
            var flag = ConfigurationManager.AppSettings["EnableWeighFinish"];

            Common.Models.WeighingRecordModel WH_Record = Common.Data.SQLDataAccess.GetWeighingRecord(pateNo);

            //打开485串口
            VzClientSDK.VZDEV_SERIAL_RECV_DATA_CALLBACK serial_recv_ = null;
            serial_handle2 = VzClientSDK.VzLPRClient_SerialStart(handle2, 0, serial_recv_, IntPtr.Zero);
            if (serial_handle2 == 0)
            {
                log.Info("相机2的485串口1打开失败!");
            }

            /* if (WH_Record != null && flag == "1")*///如果存在未完成的记录，并且参数设置里设置了是要验证称重记录完整性的。需要1、语音提醒。2、闸道不放行
            if (WH_Record != null && !WH_Record.IsFinish && flag == "1")
            {
                //1、语音提示
                //mess = $"{m_PlateNo} 禁止通行";
                mess = $"{pateNo}禁止通行";
                //TTSHelper.TTS(mess);
                log.Info($"存在未完成的称重记录：{mess}");
            }
            //else if (WH_Record.IsPay == 0)
            //{//存在未支付的称重订单
            //    mess = $"{pateNo}禁止通行";
            //    log.Info($"存在未支付的称重费用：{mess}");
            //}
            //else if (noFinish.IsPay == 0)
            //{//存在未支付的停车订单
            //    mess = $"{pateNo}禁止通行";
            //    log.Info($"存在未支付的停车费用：{mess}");
            //}
            else
            {
                ////检查是否超过授信额度，超过就不放行
                //var record = Common.Data.SQLDataAccess.GetBalancePay(WH_Record.Kh);
                //if (record != null && record.Credit <= 0)
                //{
                //    mess = $"{pateNo}禁止通行";
                //    log.Info($"超过授信额度：{record.Credit}。{mess}");
                //}
                //else
                {
                    if (noFinish != null)//车辆已经出场了，需要更新出场时间和出场状态
                    {
                        noFinish.ISFinish = true;
                        noFinish.OutDate = DateTime.Now;
                        SQLDataAccess.UpdateCarFee(noFinish);
                    }
                    AppContext.CurrentOutPlate = string.Empty;//清空离场车牌号码
                    log.Info("0x08F0 第二个 开：" + VzClientSDK.VzLPRClient_SetIOOutput(handle2, 0, 1));
                    Thread.Sleep(500);
                    log.Info("0x08F0 第二个 关：" + VzClientSDK.VzLPRClient_SetIOOutput(handle2, 0, 0));
                    Thread.Sleep(500);
                    mess = $"{pateNo}一路顺风";
                    log.Info(mess);

                    //上传超载平台数据
                    string savePath = SavePath;// AppContext.FlowControl.SavePath;
                    //Common.Models.WeighingRecordModel WH_Record = Common.Data.SQLDataAccess.GetWeighingRecord(AppContext.FlowControl.m_out_PlateNo);
                    if (WH_Record != null)
                    {
                        var channel = string.IsNullOrEmpty(WH_Record.Weigh2Name) ? "9QRX0" : WH_Record.Weigh2Name.StartsWith("9QRX0") ? "WH_Record.Weigh2Name" : "9QRX0";
                        Common.Platform.JXSCZ.JXS_CZ_Platform.UploadVWData(WH_Record, channel, savePath, savePath);
                    }
                }
            }

            //发送LED显示数据
            SendMsgToCameraLED(serial_handle2, "车牌识别", mess, DateTime.Now.ToString(), "双髻鲨汽车衡称重", mess, "g");
        }

        #endregion

        #region 16进制转换处理方法

        private string Str2Hex(string s)
        {
            string result = string.Empty;

            byte[] arrByte = Encoding.GetEncoding("GB2312").GetBytes(s);
            for (int i = 0; i < arrByte.Length; i++)
            {
                result += Convert.ToString(arrByte[i], 16) + " ";        //Convert.ToString(byte, 16)把byte转化成十六进制string 
            }

            return result.ToUpper();
        }

        #endregion


    }
}
